//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
//	File		 :	FormattedOutput.cpp
//	Contents	 :	Source file for class CFormattedOutput
//	Creation Date:	22/12/1999
//	Last Modified:	23/12/1999	lg
//	tabs width	 :	every 4 characters
//
//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888


#include <stdexcept>
#include <vector>
#include <string>
#include <algorithm>
#include <cassert>
#include "formattedoutput.h"

#ifdef _MFC_VER	// mfc specific code to follow
#include "../common/mfc_stdcpp.h"
#else
#include "../common/nonmfc_stdcpp.h"
#endif


CFormattedOutput::CFormattedOutput(unsigned textSize, const std::string& textFont)
	 :TextSize(textSize), TextFont(textFont), InProgress(false)
{
	QueuedText.reserve(128);
	cnt_Formats = 0;
}

//_______________________________________________________________________________________
//
//	BeginHeader()
//
//		Initializes
//
//		Calls the virtual function DoBeginHeader to actually write the header data
//		i.e. child does all the real work
//_______________________________________________________________________________________
void CFormattedOutput::BeginHeader()
{
	// should call EndFooter before BeginHeader again
	assert(!IsInProgress());

	SetInProgress(true);
	//initialize variables
	ClearQueuedText();
	CurrentFormat	= 0;
	DoBeginHeader();
}	


//_______________________________________________________________________________________
//
//	EndFooter()
//
//		Closes off the stream
//
//		Calls the virtual function DoEndFooter to actually write the header data
//		i.e. child does all the real work
//_______________________________________________________________________________________
void CFormattedOutput::EndFooter()
{
	// must call BeginHeader before EndFooter
	assert(IsInProgress());
	StreamQueuedText();
	DoEndFooter();
	ClearQueuedText();
	SetInProgress(false);
}

bool operator == (const CFormattedOutput::CTextFormat& a, const CFormattedOutput::CTextFormat& b)
{
	return 		a.TextColour	== b.TextColour &&
				a.BackColour	== b.BackColour &&
				a.Italic		== b.Italic	   &&
				a.Bold			== b.Bold		;
	
}

void CFormattedOutput::AddFormat(const CFormattedOutput::CTextFormat& format)
{
	// should not add formats mid-stream
	assert(!InProgress);
	
	std::vector<CFormattedOutput::CTextFormat>::iterator i = vecFormats.begin();

	for (; i != vecFormats.end(); ++i)
		if (*i == format)
			break;
		
	
	// if not contained, add
	if ( i == vecFormats.end())
	{
		formats_map_lookup[cnt_Formats] = vecFormats.size();
		vecFormats.push_back(format);
	}
	else
		formats_map_lookup[cnt_Formats] = i - vecFormats.begin();
	cnt_Formats++;
	
	//vecFormats.push_back(f);
}

//_______________________________________________________________________________________
//
//	SetFormat()
//
//		Changes the current text format. If the attributes actually change, call
//			StreamedQueuedText to purge the current queued text to the stream
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
void CFormattedOutput::SetFormat(unsigned index)
{
	// must call BeginHeader before add text etc.
	assert(IsInProgress());

	assert(index < GetFormatsCount());

/*  // optimization in cases where the same formatting attributes are duplicated in different
	// formatting indices. Probably not worthwhile. Complicates the code
	// use index 0 if possible
	if (index == 0 ||
		memcmp(&GetFormat(0), &GetFormat(index), sizeof(CTextFormat)==0))
		index = 0;
	if (CurrentFormat == index ||
		memcmp(&GetFormat(
		), &GetFormat(index), sizeof(CTextFormat)==0) )
		return;
*/
	// return if format does not change
	if (Format_map_lookup(CurrentFormat) == Format_map_lookup(index))
		return;

	StreamQueuedText();
	ClearQueuedText();

	CurrentFormat = index;
}


#ifdef _MFC_VER	// mfc specific code to follow
//_______________________________________________________________________________________
//
//	CopytoClipboard()
//
//		Copies the text stream to the clipboard in the format supplied by
//			descendant classes via GetClipboardFormat()
//		autoClipboard is an analogue of the standard c++ auto_ptr class for
//			automatically releasing the clipboard on exiting the scope
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________

bool CFormattedOutput::CopytoClipboard()
{
	auto_Clipboard clipB;
	if (!clipB.Open(0))
		return false;

	bool success = true;
	for (unsigned i = 0; i < GetFileFormatCounts(); ++i)
	{
		const std::string& clipStrm = GetClipStreamedText(i);
		// extra byte for null terminator
		unsigned dataLen = clipStrm.length()+1;

		// get system memory for passing to the clipboard
		HGLOBAL	hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dataLen);
		char*	pMem = hMem ? static_cast<char*>(GlobalLock(hMem)) : 0;

		// if cannot lock the memory for use, free it and give up
		success = (pMem != 0);
		if (!success)
			GlobalFree(hMem);
		else
		{
			// TRACE1("Formatted Output to clipboard, size= %d\r\n", dataLen);
			memcpy(pMem, clipStrm.c_str(), dataLen);
			GlobalUnlock(hMem);

			// memory is handed over to the clipboard
			success = clipB.SetClipboardData(GetClipboardFormat(i), hMem);
		}

		if (!success)
			return false;
	}
	return success;
}

//_______________________________________________________________________________________
//
//	CopytoWord()
//
//		Starts Word for Windows and uses OLE Automation to paste the output from the
//			clipboard into word
//		This seems to be the fastest way of getting formatted text into Word
//		Returns false if cannot start WinWord
//		Is RTF higher in priority than HTML?
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
MSOfficeWord::_Application* CFormattedOutput::pWordApp = 0;

void CFormattedOutput::ReleaseWordApp()
{
	// if Word has been closed by the user, the ole automation pointer
	//   will be dangling and an RPC not connected exception will ensure
	try
	{
		delete pWordApp;
	}
	catch(CException* e)
	{		e->Delete();		}	
	catch(...)
	{							}
	pWordApp = 0;
}

MSOfficeWord::_Application*	CFormattedOutput::GetWordApp()
{
	// flag to avoid exception thrown inside exception handler
	bool mustDelete = false;
	if (pWordApp)
	{
		try
		{
			MSOfficeWord::Documents docs(pWordApp->GetDocuments());
			return pWordApp;
		}
		catch(COleException* e)
		{
			mustDelete=true;
			e->Delete();
		}
	}

	// delete pointer outside of block because may produce exception itself
	if (mustDelete)
		ReleaseWordApp();


	pWordApp = new MSOfficeWord::_Application;
	if (!pWordApp->CreateDispatch("Word.Application"))
	{
		delete pWordApp;
		pWordApp = 0;
	}
	return pWordApp;

}


bool CFormattedOutput::CopyToWord(CWnd* w)
{
	if (!CopytoClipboard())
		return false;


	// start invisible copy of word
	if (!GetWordApp())
	{
		if (w)
			w->MessageBox("No compatible version of Word for Windows could be found.\r\n"
						  "Please copy and paste the annotation using the Windows Clipboard.",
						  "Error", MB_OK | MB_ICONEXCLAMATION);
		return false;
	}
	
	try
	{
		// create new document
		MSOfficeWord::Documents docs(GetWordApp()->GetDocuments());
		MSOfficeWord::_Document doc(docs.Add());
		MSOfficeWord::Selection sel(GetWordApp()->GetSelection());

		// set landscape orientation
		doc.SetLandscapeOrientation();

		// type extra space to preserve Word Document formats
		sel.TypeText(" ");
		sel.MoveLeft();

		// paste in formatted text
		sel.Paste();

		// remove extra space
		sel.Delete();

		doc.SetSpellingChecked(TRUE);
		doc.SetGrammarChecked(TRUE);

		// reveal our efforts in full glory!
		GetWordApp()->SetVisible(TRUE);

#ifndef NDEBUG
		// if debug, set is saved to true to faciliate closing
		doc.SetSaved();
#endif
	}
	catch(COleDispatchException* e)
	{

		if (w)
		{
			CString str("Word for Windows reported the following error in receiving the annotated sequences.\r\n\"");
			str += e->m_strDescription;
			str += "\"\r\nIt might be easier to paste in the results using the clipboard. ";
			w->MessageBox(str, "error"
							"Error", MB_OK | MB_ICONEXCLAMATION);
		}
		e->Delete();
		return false;
	}
	return true;
}



 /*
bool GetActiveDispatch(LPCTSTR progID, LPDISPATCH* lpDispatch);
bool CFormattedOutput::AddToWordDocument()(CWnd* w)
{
	if (!CopytoClipboard())
		return false;
	LPDISPATCH lpdispatch;
	bool runningApp = false;
	MSOfficeWord::_Application* pMyWordApp = 0;
	if (GetActiveDispatch("Word.Application", &lpdispatch))
	{
		pMyWordApp = new MSOfficeWord::_Application;
		if (pMyWordApp)
		{
			pMyWordApp->AttachDispatch(lpdispatch);
			runningApp = true;
		}
	}

	if(!pMyWordApp)
		pMyWordApp = GetWordApp();

	// start invisible copy of word
	if (!pMyWordApp)
	{
		if (w)
			w->MessageBox("No compatible version of Word for Windows could be found.\r\n"
						  "Please paste in the annotated sequences using the clipboard.",
						  "Error", MB_OK | MB_ICONEXCLAMATION);
		return false;
	}
	
	try
	{
		// paste in formatted text
		MSOfficeWord::Selection sel(pMyWordApp->GetSelection());
		sel.Paste();

	}
	catch(COleDispatchException* e)
	{

		if (w)
		{
			CString str("Word for Windows reported the following error in receiving the annotated sequences.\r\n\"");
			str += e->m_strDescription;
			str += "\"\r\nIt might be easier to paste in the results using the clipboard. ";
			w->MessageBox(str, "error"
							"Error", MB_OK | MB_ICONEXCLAMATION);
		}
		e->Delete();
		if(runningApp)
			delete pMyWordApp;
		return false;
	}
	if(runningApp)
		delete pMyWordApp;
	return true;
}


bool GetActiveDispatch(LPCTSTR progID, LPDISPATCH* lpDispatch)
{
	// map prog id to CLSID
	CLSID clsid;
	SCODE sc = AfxGetClassIDFromString(progID, &clsid);
	if (FAILED(sc))
		return false;

	// get running object
	LPUNKNOWN lpUnknown = 0;
	sc =  GetActiveObject(clsid, 0, &lpUnknown);
  	if (!SUCCEEDED(sc))
		return false;

	// query for IDispatch interface
	*lpDispatch = 0;
	sc = lpUnknown->QueryInterface( IID_IDispatch, (void**)lpDispatch);
	if (!SUCCEEDED(sc) || *lpDispatch == 0)
	{
		if (*lpDispatch)
			(*lpDispatch)->Release();
	}
	lpUnknown->Release();
	return true;
}
*/
#endif




